home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 7 / FM Towns Free Software Collection 7.iso / data / happypas / ticket.pas < prev   
Pascal/Delphi Source File  |  1993-11-30  |  13KB  |  271 lines

  1. {*********************************************************************
  2.  *  *** 自動切符販売機のシミュレーション ***                         *
  3.  *                                                                   *
  4.  *        HAPPyのサンプルプログラム                                  *
  5.  *          (作者  浅野比富美 Public Domain Software)                *
  6.  *********************************************************************}
  7.  
  8. program TicketSeller(input,output);
  9.  
  10. { 120円、150円、160円、190円、210円、250円、290円という7種類の切符を売る自動販売
  11.   機があります。これら切符を購入しお釣りを出すプログラムです。
  12.   入れることのできるお金は10円、50円、100円、500円、1000円の5種類で、コインにつ
  13.   いては20枚まで、1000円札は1枚まで入れられます。
  14.   10円~500円玉は、お釣り用としてそれぞれ20個ずつ用意されているとします。
  15.   また、入れたお金はそのままお釣りとして使えるものとします。
  16.   もちろんお釣りはなるべく少ないコイン数になるよう調整します。
  17. }
  18.  
  19. type  kind = (                                     { 入力選択番号に使う}
  20.               y10 ,y50 ,y100,y500,y1000,              { お金の種類     }
  21.               t120,t150,t160,t190,t210,t250,t290,     { 切符の種類     }
  22.               cancel,                                 { cancel ・・ 取消 }
  23.               finish                                  { finish ・・ 終了 }
  24.              ) ;
  25.       MoneyTable = array[y10..y1000] of integer ; {金種対応の枚数を格納}
  26.  
  27. var   TKingaku : array[t120..t290] of integer ; { 切符の値段表          }
  28.       kingaku  : array[y10..y1000] of integer ; { お金の値段表          }
  29.       store    : MoneyTable ;                   { 金庫のお金の枚数      }
  30.       InCoin   : MoneyTable ;                   { 投入されたお金の枚数  }
  31.       turi     : MoneyTable ;                   { 釣銭の枚数            }
  32.       InPrice  : integer    ;                   { 投入された金額        }
  33.       TPrice   : integer    ;                   { 購入する切符の値段    }
  34.       oturi    : integer    ;                   { お釣り金額            }
  35.       InitCoin : integer    ;                   { 最初の金庫金額合計    }
  36.       dummy    : Boolean    ;                   { ダミーフラグ          }
  37.  
  38. {****************************************}
  39. {*       金額合計を求める関数           *}
  40. {****************************************}
  41. function sum(number:MoneyTable) : integer;{ number の合計を返却        }
  42.   var y     : y10..y1000 ;                { for文の制御変数(金種)      }
  43.       total : integer;                    { 計算エリア                 }
  44. begin {sum}
  45.   total := 0 ;
  46.   for y := y10 to y1000 do  total := total + number[y] * kingaku[y] ;
  47.   sum := total
  48. end {sum};
  49.  
  50. {****************************************}
  51. {*        初期設定                      *}
  52. {****************************************}
  53. procedure init ;
  54.   var y : y10..y500 ;                     { for文の制御変数(金種)      }
  55. begin {init}
  56.   TKingaku[t120] := 120 ; TKingaku[t150] := 150 ; TKingaku[t160] := 160;
  57.   TKingaku[t190] := 190 ; TKingaku[t210] := 210 ; TKingaku[t250] := 250;
  58.   TKingaku[t290] := 290 ;                 { 切符の値段設定             }
  59.   kingaku[ y10]  :=  10 ; kingaku[  y50] :=   50; kingaku[y100]  := 100;
  60.   kingaku[y500]  := 500 ; kingaku[y1000] := 1000;  { お金の額面設定    }
  61.   for y := y10 to y500 do store[y] := 20 ;{ 10円から500円までは20枚    }
  62.   store[y1000] := 0 ;                     { 1000円は蓄えなし           }
  63.   InitCoin := sum(store)                  { 最初の金庫合計を算出       }
  64. end {init} ;
  65.  
  66. {****************************************}
  67. {*        金種の出力                    *}
  68. {****************************************}
  69. procedure PrintCoin(print:MoneyTable) ; { print : 出力対象             }
  70.   var y : y10..y1000 ;                  { for文の制御変数(金種)        }
  71. begin {PrintCoin}
  72.   if sum(print) = 0 then writeln        { 0円ならば出力しない          }
  73.   else
  74.   begin
  75.     write('(') ;
  76.     for y := y1000 downto y10 do        { それぞれの金種について       }
  77.       if print[y] <> 0 then write(kingaku[y]:2,'円=',print[y]:1,'枚 ');
  78.     writeln(')')
  79.   end
  80. end {PrintCoin} ;
  81.  
  82. {****************************************}{ oturiが、bankから払えれば真を}
  83. {*        釣銭の計算                    *}{ 返す。 釣銭の金種はturiに格納}
  84. {****************************************}{ bankは釣銭支払い後の状態になる}
  85. function CompTuri(oturi:integer ; var bank:MoneyTable) : Boolean ;
  86.   var d          : integer    ;        { 計算エリア                    }
  87.       y          : y10..y1000 ;        { for文の制御変数(金種)         }
  88.       SaveY1000  : integer    ;        { 金庫の1000円枚数退避用        }
  89. begin {CompTuri}
  90.   SaveY1000 := bank[y1000] ;           { 今の1000円札を退避            }
  91.   for y := y10 to y500 do              { 釣銭として使えるお金を求める  }
  92.     bank[y] := bank[y] + InCoin[y] ;   { 10~500円は金庫と投入コイン      }
  93.   bank[y1000] := InCoin[y1000] ;       { 1000円札は今入れられたもの    }
  94.   for y := y1000 downto y10 do         { 1000円から順に釣りを計算      }
  95.   begin
  96.     d := oturi div kingaku[y] ;               { 必要コイン数           }
  97.     if d  > bank[y] then d := bank[y] ;       { 金庫のコイン全部       }
  98.     bank[y] := bank[y] - d ;                  { 必要コインを引く       }
  99.     turi[y] := d ;                            { 釣銭を格納             }
  100.     oturi   := oturi - (kingaku[y] * d)       { 残りのお釣り計算       }
  101.   end  ;
  102.   bank[y1000] := bank[y1000] + SaveY1000 ;    { 1000円札の枚数更新     }
  103.   CompTuri := oturi = 0                       { 釣銭不足でなければ真   }
  104. end {CompTuri};
  105.  
  106. {****************************************}
  107. {*        入力操作                      *}
  108. {****************************************}
  109. function operation : Boolean   ;        { 終わりが選択されたら偽を返す }
  110.   const MaxCoin  = 20          ;        { 最大コイン投入可能枚数       }
  111.   var t          : t120..t290  ;        { for文の制御変数(切符の種類)  }
  112.       n          : integer     ;        { 入力番号                     }
  113.       s          : kind        ;        { 選択番号                     }
  114.       oturi      : integer     ;        { お釣り金額                   }
  115.       TempStore  : MoneyTable  ;        { storeのワーク                }
  116.       number     : integer     ;        { お金の枚数                   }
  117.       CoinNumber : integer     ;        { コイン枚数投入の管理に使用   }
  118.       ok         : Boolean     ;        { 選択番号入力okフラグ         }
  119.       selector   : set of kind ;        { 入力可能な選択番号集合       }
  120.  
  121.   {************************************}
  122.   {*   投入コインエリアのクリア処理   *}
  123.   {************************************}
  124.   procedure clear ;
  125.     var y : y10..y1000 ;                { for文の制御変数(金種)        }
  126.   begin {clear}
  127.     CoinNumber := 0 ;                   { 投入コイン枚数クリア         }
  128.     for y := y10 to y1000 do InCoin[y] := 0 ;
  129.     selector := [y10..y1000,finish]     { 最初に選べる選択番号集合     }
  130.   end {clear} ;
  131.  
  132.   {************************************}
  133.   {*  入力不可の項目に*を付ける処理   *}
  134.   {************************************}
  135.   procedure PutAster(s:kind) ;          { sが不可の時 * をつける       }
  136.   begin {PutAster}
  137.     if s in selector then write(' ') else write('*')
  138.   end {PutAster} ;
  139.  
  140.   {************************************}
  141.   {*          釣銭切れ出力            *}
  142.   {************************************}
  143.   procedure OutOfTuri ;
  144.     var y : y10..y500 ;                 { for文の制御変数(金種)        }
  145.         fusoku : Boolean ;              { 釣銭切れがある時 真          }
  146.   begin {OutOfTuri}
  147.     fusoku := false ;
  148.     for y := y10 to y500 do             { 釣銭切れがあるか調べる       }
  149.       fusoku := fusoku or (store[y]+InCoin[y] = 0) ;
  150.     if fusoku then                      { 釣銭切れがある時             }
  151.     begin
  152.       write('釣銭切れ (') ;
  153.       for y := y10 to y500 do           { 釣銭切れのお金を表示         }
  154.         if store[y] + InCoin[y] = 0 then write(kingaku[y]:2,'円 ') ;
  155.       writeln(')')
  156.     end
  157.   end {OutOfTuri} ;
  158.  
  159.   {************************************}
  160.   {*  選択番号のガイドを出力する処理  *}
  161.   {************************************}
  162.   procedure guide ;
  163.     var y : y10..y1000 ;                  { for文の制御変数(金種)        }
  164.         t : t120..t290 ;                { for文の制御変数(切符の種類)  }
  165.   begin {guide}
  166.     writeln ;
  167.     write('投入金額=',InPrice:4,'円 ');
  168.     PrintCoin(InCoin) ;                 { 投入コインの詳細を出力       }
  169.     OutOfTuri         ;                 { 釣銭切れ情報出力             }
  170.     writeln(
  171. '========================= 切符販売機 選択番号一覧 =========================');
  172.     write('金種選択(');                          { 金種選択の番号出力  }
  173.     for y := y10 to y1000 do
  174.     begin
  175.       PutAster(y) ; write(ord(y):1,':',kingaku[y]:3,'円 ')
  176.     end ;
  177.     writeln(')');
  178.     write('切符選択(');                          { 切符選択の番号出力  }
  179.     for t := t120 to t290 do
  180.     begin
  181.       PutAster(t) ; write(ord(t):1,':',TKingaku[t]:3,'円 ')
  182.     end;
  183.     writeln(')');
  184.     write('その他  ( ');                         { その他の番号出力    }
  185.     PutAster(cancel) ; write(ord(cancel):2,': 取消 ');
  186.     PutAster(finish) ; writeln(ord(finish):2,': 終わり )');
  187.     writeln(
  188. '===========================================================================')
  189.   end {guide} ;
  190.  
  191. begin {operation ---------入力操作のメイン処理-------------------------}
  192.   writeln ;
  193.   clear   ;                             { 投入コインエリアのクリア     }
  194.  
  195.   repeat                                { 切符選択または終わりまで     }
  196.  
  197.     InPrice := sum(InCoin) ;            { 投入合計金額を計算           }
  198.     if InPrice   <> 0       then selector := selector+[cancel]    ;{取消有効  }
  199.     if CoinNumber = MaxCoin then selector := selector-[y10..y500] ;{コイン不可}
  200.     for t := t290 downto t120 do        { 釣銭不足とならないか調べる   }
  201.     begin
  202.       oturi := InPrice - TKingaku[t] ;  { お釣りを仮定する             }
  203.       if oturi >= 0 then                { 金額的に購入可能な時         }
  204.       begin
  205.         TempStore := store ;            { 釣銭が出せるか調べる         }
  206.         if CompTuri(oturi,TempStore) then  { 釣銭が出せる              }
  207.           selector := selector + [t]    { その切符は購入可能           }
  208.       end
  209.     end ;
  210.  
  211.     guide           ;                   { 選択番号ガイド出力           }
  212.     ok := false     ;
  213.     repeat                             { 正しい選択番号が入力されるまで}
  214.       write('選択番号を入力して下さい(*印の番号は入力不可) ? ') ;
  215.       readln(n) ;                       { 選択番号を入力               }
  216.       if (ord(y10) <= n) and (n <= ord(finish)) then
  217.       begin                             { 選択番号に対応した種別を得る }
  218.         s := y10 ; while ord(s) <> n do s := succ(s) ;
  219.         ok := s in selector           { 入力可能な選択番号の時リピート抜け}
  220.       end
  221.     until ok ;
  222.  
  223.     selector := selector - [finish] ;   { 終わりを選べなくする         }
  224.     if s = cancel then                  { 取消が選択された             }
  225.     begin
  226.       write('投入された',InPrice:2,'円を返却します ') ;
  227.       PrintCoin(InCoin) ;               { 投入コインの種別を出力       }
  228.       clear                             { 投入コインエリアをクリア     }
  229.     end
  230.     else if s in [y10..y500] then       { 10円~500円が選択された      }
  231.     begin
  232.       repeat                            { MaxCoin枚まで                }
  233.         write(kingaku[s]:2,'円を何枚入れますか (1~',
  234.               MaxCoin-CoinNumber:2,') ? ') ;
  235.         readln(number)                  { 枚数入力                     }
  236.       until (1<=number) and (number<=MaxCoin-CoinNumber) ;
  237.       InCoin[s]  := InCoin[s] + number; { 投入コインに加える           }
  238.       CoinNumber := CoinNumber + number { 投入コイン枚数カウントアップ }
  239.     end
  240.     else if s = y1000 then              { 1000円は1枚しか入らない      }
  241.     begin
  242.       Incoin[y1000] := Incoin[y1000] + 1  ;
  243.       selector      := selector - [y1000]   { 以後1000円札投入不可     }
  244.     end
  245.  
  246.   until s in [t120..t290,finish] ;      { 切符、終わりが選ばれたら止める}
  247.  
  248.   writeln ;
  249.   if s <> finish then TPrice := TKingaku[s] ;{ 切符の値段              }
  250.   operation := s <> finish                   { 終わりでなければ 真     }
  251. end {operation};
  252.  
  253. {****************************************}
  254. {*        メイン処理                    *}
  255. {****************************************}
  256. begin {main}
  257.   init  ;                               { 初期設定                     }
  258.   while operation do                    { 終わりが指示されるまで発券   }
  259.   begin
  260.     writeln(TPrice:3,'円の切符を発券します ');
  261.     oturi := InPrice - TPrice       ;
  262.     write('釣銭は',oturi:2,'円 ')   ;   { 釣銭合計を表示               }
  263.     dummy :=  CompTuri(oturi,store) ;   { 釣銭計算 (必ず釣銭が出せる)  }
  264.     PrintCoin(turi)                     { 釣銭詳細を表示               }
  265.   end ;
  266.   writeln('営業終了');                  { 終了処理                     }
  267.   writeln('  売上金   = ',sum(store)-InitCoin:5,'円'); { 売上金額表示  }
  268.   writeln('  金庫の中 = ',sum(store):5,'円');          { 金庫の合計金額}
  269.   PrintCoin(store)                      { 金庫のお金の詳細を表示       }
  270. end {main}.
  271.